/*
 * core.c
 *
 *  Created on: Aug 3, 2009
 *      Author: jacky
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include <sys/time.h>
#include <errno.h>
#include <stdarg.h>
#include <fcntl.h>
#include <unistd.h>
#include "core.h"

static RequestMethod getRequestMethod(void)
{
	char *requestMethod = getenv("REQUEST_METHOD");
	if ( NULL == requestMethod )
	{
		DEBUG_ERROR("This is an cgi program.\n"
				"please run it in cgi container such as mini_httpd, thttpd, apache etc.\n"
				"ENV not contain \"REQUEST_METHOD\"\n");
		exit(CORE_FAIL);
	}
	return strcasecmp("get", requestMethod) ? POST : GET;
}

static int getCtrlId(Controller c[], int controllersLength, char *ctrl)
{
	int i;
	for (i = 1; i < controllersLength; i++)
	{
		if ( strcmp(c[i].name, ctrl) == 0 )
			return i;
	}
	return 0;
}
static int getActionId(Action a[], int actionLength, char *action)
{
	int i;
	for (i = 1; i < actionLength; i++)
	{
		if ( NULL == a[i].name && strcmp(a[i].name, action) == 0 )
		{
			return i;
		}
	}
	return 0;
}
/**
 * 初始化 Request
 * @return CORE_OK:          成功
 *         CORE_ERROR_CTLID: CtrlID错误,请求了未定义的Controller
 *         CORE_ERROR_ACTID: ActionID错误,请求了未定义的Aciton
 */
CoreStatus initRequest(HttpRequest *req, Controller controllers[],
					   int controllersLength)
{
	CoreStatus result = CORE_OK;
	char ctrl[MAX_NAME_SIZE];
	char action[MAX_NAME_SIZE];
	assert(req);
	assert(controllers);
	req->curCtrl = NULL;
	req->curAction = NULL;
	req->queryString = getenv("QUERY_STRING") ? : "";
	req->method = getRequestMethod();

	/* 解析请求 */
	if ( sscanf(req->queryString, "do=/%[^/]/%[^/]", ctrl, action) > 0 )
	{
		/* set ctrlid and actionid */
		if ( !(req->ctrlid = atoi(ctrl)) )
		{
			req->ctrlid = getCtrlId(controllers, controllersLength, ctrl);
		}
		if ( !(req->actionid = atoi(action)) )
		{
			req->actionid = getActionId(controllers[req->ctrlid].actions,
										controllers[req->ctrlid].actionLength,
										action);

		}
	}
	else
	{
		cgiError("<html>"
				"<head></head>"
				"<body><h1>Request Error</h1><a href=\"?do=/1/1/\">default action</a></body>"
				"</html>");
	}
	//	req->ctrlid = getCtrlId(req);
	//	req->actionid = getActionId(req);
	if ( req->ctrlid < controllersLength && req->ctrlid > 0 )
	{
		req->curCtrl = &controllers[req->ctrlid];
		if ( req->actionid < req->curCtrl->actionLength && req->actionid > 0 )
		{
			req->curAction = &req->curCtrl->actions[req->actionid];
		}
		else
		{
			result = CORE_ERROR_ACTID;
		}
	}
	else
	{
		result = CORE_ERROR_CTLID;
	}
	return result;
}

CoreStatus initResponse(HttpResponse *rsp)
{
	memset(rsp, 0, sizeof(HttpResponse));
	rsp->autoRender = 1;
	//	rsp->status = 0;
	//	rsp->layout = NULL;
	//	rsp->view = NULL;
	rsp->Out = stdout;

	return CORE_OK;
}
void destoryResponse(HttpResponse *rsp)
{
	/* TODO:Jacky 销毁 Response */
}
void destoryRequest(HttpRequest *req)
{
	/* TODO:Jacky 销毁 Request */
}
#ifdef DEBUG
/* 计时变量,用来测试性能 */
static struct timeval __start, __stop;
/**
 *   计算两个时间的间隔，得到时间差
 *   @param   struct   timeval*   resule   返回计算出来的时间
 *   @param   struct   timeval*   x             需要计算的前一个时间
 *   @param   struct   timeval*   y             需要计算的后一个时间
 *   @return   -1   failure   ,0   success
 **/
static int timeval_subtract(struct timeval* result, struct timeval* x,
							struct timeval* y)
{

	if ( x->tv_sec > y->tv_sec )
		return -1;

	if ( (x->tv_sec == y->tv_sec) && (x->tv_usec > y->tv_usec) )
		return -1;

	result->tv_sec = (y->tv_sec - x->tv_sec);
	result->tv_usec = (y->tv_usec - x->tv_usec);

	if ( result->tv_usec < 0 )
	{
		result->tv_sec--;
		result->tv_usec += 1000000;
	}

	return 0;
}
/* cgi 开始计时*/
static void start_timer()
{
	gettimeofday(&__start, 0);
}
/* 调用此函数前先调用 start_timer(), 框架在DEBUG模式下自动调用start_timer()函数
 *
 * 返回 cgiMain 开始执行到调用此函数经历的时间 */
struct timeval elapsed_time()
{
	struct timeval diff;
	gettimeofday(&__stop, 0);
	timeval_subtract(&diff, &__start, &__stop);
	return diff;
}

void print4debug(const char* format, ...)
{
	FILE *fp = NULL;
	if ( (fp = fopen("/tmp/debug", "w")) != NULL )
	{
		va_list arg;
		va_start(arg,format);
		vfprintf(fp, format, arg);
		va_end(arg);

		fclose(fp);
	}
}

#endif /* DEBUG */

/* cgi 入口函数 */
int main()
{
	int result;
	print4debug("[%s] %s():%d\n",__FILE__,__FUNCTION__,__LINE__);
#ifdef DEBUG
	start_timer();
#endif /* DEBUG */
	result = cgiMain();
	return result;
}
